/*
Dominique Jannone
Guillaume Marre
Yohan Ojeda
Laurent Schiavon
*/
package Econf_Audio;

import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.control.*;
import java.util.*;
import java.io.*;
import javax.media.rtp.*;

import java.net.InetAddress;
import javax.media.control.BufferControl;

import model.Conference;
import model.eConf;

import org.omg.CORBA.PUBLIC_MEMBER;

import com.sun.media.sdp.SessionDescription;
import java.util.logging.Logger;
import java.util.logging.Level;




public class Emetteur_client extends Thread{

	// Attrinuts
    private static int portE;
	private static String ipServer;
	public static RTPManager[] rtpm;
	private boolean fin;
	CaptureDeviceInfo di;
	private static int formatPriority2 = -1;
	private static int formatPriority1 = -1;
	private static int formatPriority3 = -1;
	//log
		public static final Logger logger = Logger.getLogger(Emetteur_client.class.getName());

	// Constructeur
	public Emetteur_client(int portE, String IpServeur) {
		this.portE = portE;
		this.ipServer = IpServeur;
		fin = false;
	}

	// Methode init
		/**
         * @param args
         */
		public void run() {
			init();
			while (!fin){
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
				}
			}
		}
		
		public void closeThread(){
			fin = true;
		}
	
        public void init() {
        	
        	CaptureDeviceInfo diStocke = eConf.getDi();
        	Processor FichierCessor = null;
        	if (diStocke == null){
        		
        		   int                              i, j;
                   int                              nCount=0;
                   CaptureDeviceInfo   infoCaptureDevice;
                   Format                    arrFormats [];
                   // TODO Auto-generated method stub
                   di=null;
                   logger.log(Level.INFO,"test 1");
//                    // Get the CaptureDeviceInfo for the live audio capture device 
//                    Vector deviceList = CaptureDeviceManager.getDeviceList(new 
//                                                                   AudioFormat("linear", 22050, 16, 1)); 
//                    if (deviceList.size()>0)
//                    {
//                            nCount=deviceList.size();
//                            logger.log(Level.INFO,"Enumerating devicelist");
//                              for ( i = 0;  i < nCount;  i++ ) {
//                                           infoCaptureDevice = (CaptureDeviceInfo) deviceList.elementAt ( i );
//                                           arrFormats = infoCaptureDevice.getFormats ();
//                                           for ( j = 0;  j < arrFormats.length;  j++ ) {
//                                                   if ( arrFormats[j] instanceof AudioFormat ) {
//                                                           //vectorAudioDevices.addElement ( infoCaptureDevice );
//                                                	   logger.log(Level.INFO,""+infoCaptureDevice);
//                                                           break;
//                                                   }
//                                           }
//                                   }
//                    }else{System.exit(0);}
//                    
//                    di = (CaptureDeviceInfo) deviceList.elementAt(0);
                    
                    

                    
                  di = CaptureDeviceManager.getDevice("JavaSound audio capture");
                  eConf.setDi(di);
                          MediaLocator FichierLocator = di.getLocator();
                          
                          
//                        Déclaration du processeur
                          
                          DataSource ds=null;
                          try{
                                  //Création du Processor à partir du MediaLocator
                                  try{
                                          ds = Manager.createDataSource(FichierLocator);
                                          
                                          
                                  }
                                  catch(Exception e){
                                	  logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                                  	
                                  }  
                                  // Check to see if there's a buffer control on the data source.
                                  // It could be that we are using a capture data source.
//                                  Control c = (Control)ds.getControl("javax.media.control.BufferControl");
//                                  if (c != null){
//                                          ((BufferControl)c).setBufferLength(1);
//                                          ((BufferControl)c).setMinimumThreshold(2);
//                                          ((BufferControl)c).setEnabledThreshold(true);
  //
//                                  }
                                          FichierCessor = Manager.createProcessor(ds);
                                          eConf.setFichierCessor(FichierCessor);
                                  
                                  //Appel des fonctions qui vont permettre le lancement du flux RTP
                                  configure(FichierCessor);
                                  SetSupportedFormat(FichierCessor);
                                  //passer dans l'etat realized du processor
                                  realize(FichierCessor);
                                  //start  
                                  Demarre(FichierCessor); 
                                  launchRTPManager(FichierCessor);
                          }
                          catch(IOException e)
                          {
                        	  logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                          }
                          catch(NoProcessorException e)
                          {
                        	  logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                          }
        		
        	}else{
        		di= diStocke;
        		FichierCessor= eConf.getFichierCessor();
        		//start  
        		 launchRTPManager(FichierCessor);
        		
        	}
            
        	

        }
        public static Processor configure(Processor p)  
        {
                //Attendre tant que le Processor n'est pas configuré.
                while(p.getState() < Processor.Configured)
                {
                        //Configuration du Processor
                        p.configure();
                }
                return p;
        }
        public static void SetSupportedFormat(Processor p)
        {
                //On met la description du contenu de sortie à RAW_RTP
                ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
                p.setContentDescriptor(cd);
                
                //On obtient les différentes pistes du processor
                TrackControl track[] = p.getTrackControls();
                for(int i = 0; i < track.length; i++)
                {
                        //on obtient les formats supportés pour cette piste
                        Format suppFormats[] = track[i].getSupportedFormats();
                        //Si il y a au moins un format supporté
                        //System.out.println();
                        for ( int t=0; t < suppFormats.length;t++)
                        {
                                logger.log(Level.INFO,"RTP supported format: "+suppFormats[t]);
                             // ADD 
                                if (suppFormats[t].getEncoding().equals(AudioFormat.DVI_RTP)) formatPriority1 =t;
                                if (suppFormats[t].getEncoding().equals(AudioFormat.GSM_RTP)) formatPriority2 =t;
                                if (suppFormats[t].getEncoding().equals(AudioFormat.ULAW_RTP)) formatPriority3 =t;
                        
                        }
                        if(suppFormats.length > 0)
                        {   //suppFormats.length-2
                        	// ADD Priority 
                        	int formatUse;
                        	if (formatPriority1 != -1) formatUse = formatPriority1;
                        	else if (formatPriority2 != -1) formatUse = formatPriority2;
                        	else if (formatPriority3 != -1) formatUse = formatPriority3;
                        	else formatUse = suppFormats.length-1;
                        	
                        	track[i].setFormat(suppFormats[formatUse]);
//                                System.err.println("Track " + i +" est transmis as :"+suppFormats[formatUse]);
                                logger.log(Level.INFO,"Track " + i +" est transmis as : "+suppFormats[formatUse]);
                                if (track[i].getFormat() instanceof AudioFormat) {
                                        int packetRate = 5;
                                        PacketSizeControl pktCtrl = (PacketSizeControl) p.getControl(PacketSizeControl.class.getName());
                                        if (pktCtrl != null) {
                                                try {
                                                         pktCtrl.setPacketSize(getPacketSize(track[i].getFormat(), packetRate));
                                                        //pktCtrl.setPacketSize(pktCtrl.getPacketSize());
                                                        //pktCtrl.setPacketSize(1);
                                                }
                                                catch (IllegalArgumentException e) {
                                                        pktCtrl.setPacketSize(80);
                                                        // Do nothing
                                                }
                                        }
                                }

                                
                                
                                
                        }
                        else
                        {
                                track[i].setEnabled(false);
                        }
                }
                
                
        }
        
        private static int getPacketSize(Format codecFormat, int milliseconds) throws IllegalArgumentException {
                String encoding = codecFormat.getEncoding();
                if (encoding.equalsIgnoreCase(AudioFormat.GSM) ||
                                encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
                        return milliseconds * 4; // 1 byte per millisec
                }
                else if (encoding.equalsIgnoreCase(AudioFormat.ULAW) ||
                                encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
                        return milliseconds * 8;
                }
                else {
                        throw new IllegalArgumentException("Unknown codec type");
                }
        }

        
        public static Processor realize(Processor p)
        {
                //Attendre tant que le Processor n'est pas réalisé.
                while(p.getState() < Processor.Realized)
                {               
                        //Réalisation du Processor
                        p.realize();
                }
                return p;
        }
        
        public static void Demarre(Processor p)
        {
                //Demarrage du Processor
                p.start();
                logger.log(Level.INFO,"Processor started");
        }
        
       

        public static void launchRTPManager(Processor p)
        {
                //Creation du DataSource correspondant au Processor
                DataSource OutputSource = p.getDataOutput();
                PushBufferDataSource pbds = (PushBufferDataSource)OutputSource;
                PushBufferStream pbss[] = pbds.getStreams();                      
                //Nouvelle Instance d'un RTPManager       
                rtpm = new RTPManager[pbss.length];
                
                
                //System.out.println("taille:" +pbss.length);
                //RTPManager rtpm;
                for(int i=0; i < pbss.length;i++)       
                {
                        try{
                                
                        		rtpm[i] = RTPManager.newInstance();
                        		
                                //Création d'une SessionAddress 
                                SessionAddress localaddr = new SessionAddress(InetAddress.getLocalHost(),3333);
                                //Initialisation du RTPManager
                                rtpm[i].initialize(localaddr);
                                //Création d'une SessionAddress 
                                SessionAddress destaddr = new SessionAddress(InetAddress.getByName(ipServer),portE);
                                //Ajout de cette SessionAddress dans le RTPManager
                                rtpm[i].addTarget(destaddr);
                                logger.log(Level.INFO,"Creation RTP session "+ipServer+" port : "+portE);                                    
                                //Creation d'un SendStream à partir du DataSource                               
                                SendStream ss2 = rtpm[i].createSendStream(OutputSource,i);
                                //Demarrage du SendStream
                                ss2.start();
                                logger.log(Level.INFO,"Started ");
                        }
                        catch(Exception e)
                        {
                        	logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                        }         
                        
                }       
        }
        
}
